package com.inttra.generator.plugin;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;

public class DomainPlugin extends PluginAdapter {

	private static final String PREFIX = "f";
	private boolean isEnum = false;

	public DomainPlugin() {
	}

	public boolean validate(List<String> warnings) {
		return true;
	}

	@Override
	public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
		if (isEnum()) {
			return false;
		}

		decorateTopLevelClass(topLevelClass, introspectedTable);

		List<IntrospectedColumn> columns;
		if (introspectedTable.getRules().generateRecordWithBLOBsClass()) {
			columns = introspectedTable.getNonBLOBColumns();
		} else {
			columns = introspectedTable.getAllColumns();
		}

		generateDefaultConstruct(topLevelClass, columns, introspectedTable);
		generateConstructWithPk(topLevelClass, columns, introspectedTable);

		generateInitVars(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);
		generateInitChildVars(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);

		return true;
	}

	@Override
	public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
		if (isEnum()) {
			return false;
		}

		decorateTopLevelClass(topLevelClass, introspectedTable);

		generateDefaultConstruct(topLevelClass, introspectedTable.getPrimaryKeyColumns(), introspectedTable);
		generateConstructWithPk(topLevelClass, introspectedTable.getPrimaryKeyColumns(), introspectedTable);

		generateInitVars(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);
		generateInitChildVars(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);

		return true;
	}

	@Override
	public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
		if (isEnum()) {
			return false;
		}

		decorateTopLevelClass(topLevelClass, introspectedTable);

		generateDefaultConstruct(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);
		generateConstructWithPk(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);

		generateInitVars(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);
		generateInitChildVars(topLevelClass, introspectedTable.getAllColumns(), introspectedTable);

		return true;
	}

	/**
	 * modify top level class.
	 * 
	 * @param topLevelClass
	 * @param introspectedTable
	 */
	protected void decorateTopLevelClass(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
		// add import types
		topLevelClass.addImportedType(new FullyQualifiedJavaType("com.inttra.common.annotations.Column"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType("com.inttra.common.annotations.Table"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType("com.inttra.shared.data.tnx.CTnxRootRecord"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType("com.inttra.common.util.CDate"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType("java.math.BigDecimal"));
		topLevelClass.addImportedType(new FullyQualifiedJavaType("com.inttra.shared.CField"));

		// add interface and supper class
		String className = topLevelClass.getType().getShortName().substring(1);
		topLevelClass.addSuperInterface(new FullyQualifiedJavaType("IRW" + className));
//		topLevelClass.addSuperInterface(new FullyQualifiedJavaType("ITnxRecordListContainer"));
		topLevelClass.setSuperClass("CTnxRootRecord<" + topLevelClass.getType().getShortName() + ">");

		// add annotations
		topLevelClass.addAnnotation("@SuppressWarnings(\"serial\")");

		StringBuilder sb = new StringBuilder();
		sb.append("@Table");
		sb.append("(");
		sb.append("name = \"" + introspectedTable.getFullyQualifiedTable().getIntrospectedTableName() + "\"");
		sb.append(", primaryKey = {\"" + introspectedTable.getPrimaryKeyColumns().get(0).getActualColumnName() + "\"}");
		sb.append(", valueConverter = " + topLevelClass.getType().getShortName() + "Converter.class");
		sb.append(")");

		topLevelClass.addAnnotation(sb.toString());
	}

	/**
	 * add default construct.
	 * 
	 * @param topLevelClass
	 * @param introspectedColumns
	 * @param introspectedTable
	 */
	protected void generateDefaultConstruct(TopLevelClass topLevelClass, List<IntrospectedColumn> introspectedColumns,
			IntrospectedTable introspectedTable) {
		Method method = new Method();
		method.setConstructor(true);
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setName(topLevelClass.getType().getShortName());

		method.addBodyLine("super();");
		method.addBodyLine("initVars();");
		method.addBodyLine("initChildVars(false);");

		topLevelClass.addMethod(method);
	}

	/**
	 * add construct with parameter PK.
	 * 
	 * @param topLevelClass
	 * @param introspectedColumns
	 * @param introspectedTable
	 */
	protected void generateConstructWithPk(TopLevelClass topLevelClass, List<IntrospectedColumn> introspectedColumns,
			IntrospectedTable introspectedTable) {
		Method method = new Method();
		method.setConstructor(true);
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setName(topLevelClass.getType().getShortName());
		method.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(), "pk"));
		method.addBodyLine("super(pk);");
		method.addBodyLine("initVars();");
		String upperField = Character.toUpperCase(introspectedTable.getPrimaryKeyColumns().get(0).getJavaProperty()
				.charAt(0))
				+ introspectedTable.getPrimaryKeyColumns().get(0).getJavaProperty().substring(1);
		method.addBodyLine("set" + upperField + "(pk);");
		method.addBodyLine("initChildVars(true);");

		topLevelClass.addMethod(method);
	}

	/**
	 * add initVars method.
	 * 
	 * @param topLevelClass
	 * @param introspectedColumns
	 * @param introspectedTable
	 */
	protected void generateInitVars(TopLevelClass topLevelClass, List<IntrospectedColumn> introspectedColumns,
			IntrospectedTable introspectedTable) {
		Method method = new Method();

		method.setVisibility(JavaVisibility.PUBLIC);
		method.setName("initVars");

		for (IntrospectedColumn introspectedColumn : introspectedColumns) {
			String upperField = Character.toUpperCase(introspectedColumn.getJavaProperty().charAt(0))
					+ introspectedColumn.getJavaProperty().substring(1);
			method.addBodyLine(PREFIX + upperField + " = new CField<"
					+ introspectedColumn.getFullyQualifiedJavaType().getShortName() + ">(this);");
		}

		topLevelClass.addMethod(method);
	}

	/**
	 * add initChildvars method.
	 * 
	 * @param topLevelClass
	 * @param introspectedColumns
	 * @param introspectedTable
	 */
	protected void generateInitChildVars(TopLevelClass topLevelClass, List<IntrospectedColumn> introspectedColumns,
			IntrospectedTable introspectedTable) {
		Method method = new Method();

		method.setVisibility(JavaVisibility.PUBLIC);
		method.setName("initChildVars");
		method.addParameter(new Parameter(FullyQualifiedJavaType.getBooleanPrimitiveInstance(), "load"));

		method.addBodyLine("// TODO add list");

		topLevelClass.addMethod(method);
	}

	/**
	 * modify field.
	 */
	@Override
	public boolean modelFieldGenerated(Field field, TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
			IntrospectedTable introspectedTable, ModelClassType modelClassType) {
		if (isEnum()) {
			return false;
		}

		String upperField = Character.toUpperCase(field.getName().charAt(0)) + field.getName().substring(1);

		// add annotation for each field
		StringBuilder sb = new StringBuilder();
		sb.append("@Column");
		sb.append("(");
		sb.append("name = \"" + introspectedColumn.getActualColumnName() + "\"");
		sb.append(", getter = \"get" + upperField + "\"");
		sb.append(", setter = \"set" + upperField + "\"");
		sb.append(")");
		field.addAnnotation(sb.toString());

		// decorate field type
		field.setType(new FullyQualifiedJavaType("CField<" + field.getType().getShortName() + ">"));

		// decorate field name
		field.setName(PREFIX + upperField);

		return true;
	}

	/**
	 * modify getter method.
	 */
	@Override
	public boolean modelGetterMethodGenerated(Method method, TopLevelClass topLevelClass,
			IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
		if (isEnum()) {
			return false;
		}

		method.getBodyLines().clear();

		method.setReturnType(new FullyQualifiedJavaType(introspectedColumn.getFullyQualifiedJavaType().getShortName()));
		String upperField = Character.toUpperCase(introspectedColumn.getJavaProperty().charAt(0))
				+ introspectedColumn.getJavaProperty().substring(1);
		method.addBodyLine("return " + PREFIX + upperField + ".get();");

		return true;
	}

	/**
	 * modify setter method.
	 */
	@Override
	public boolean modelSetterMethodGenerated(Method method, TopLevelClass topLevelClass,
			IntrospectedColumn introspectedColumn, IntrospectedTable introspectedTable, ModelClassType modelClassType) {
		if (isEnum()) {
			return false;
		}

		// modify parameter type
		List<Parameter> parameters = method.getParameters();
		for (int i = 0; i < parameters.size(); i++) {
			if ("Date".equals(parameters.get(i).getType().getShortName())) {
				parameters.set(i, new Parameter(new FullyQualifiedJavaType("CDate"), parameters.get(i).getName()));
			}
		}

		// modify body content
		method.getBodyLines().clear();
		String upperField = Character.toUpperCase(introspectedColumn.getJavaProperty().charAt(0))
				+ introspectedColumn.getJavaProperty().substring(1);

		// TODO parameter type
		method.addBodyLine(PREFIX + upperField + ".set(" + introspectedColumn.getJavaProperty() + ");");

		return true;
	}

	/**
	 * add interface.
	 */
	@Override
	public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {

		List<GeneratedJavaFile> javaFiles = new ArrayList<GeneratedJavaFile>();

		List<CompilationUnit> compilationUnits = new ArrayList<CompilationUnit>();

		if (isEnum()) {
			generateEnumClass(compilationUnits, introspectedTable);
		} else {
			generateReadWriteInterface(compilationUnits, introspectedTable);
			generateReadOnlyInterface(compilationUnits, introspectedTable);
			generateConverter(compilationUnits, introspectedTable);
		}

		for (CompilationUnit compilationUnit : compilationUnits) {
			GeneratedJavaFile javaFile = new GeneratedJavaFile(compilationUnit, context
					.getJavaModelGeneratorConfiguration().getTargetProject());
			javaFiles.add(javaFile);
		}

		return javaFiles;
	}

	/**
	 * Add enum.
	 * 
	 * @param compilationUnits
	 * @param introspectedTable
	 */
	private void generateEnumClass(List<CompilationUnit> compilationUnits, IntrospectedTable introspectedTable) {
		String className = introspectedTable.getTableConfiguration().getDomainObjectName();
		String targetPackage = context.getJavaModelGeneratorConfiguration().getTargetPackage();
		TopLevelClass cls = new TopLevelClass(targetPackage + "." + className);

		cls.addImportedType(new FullyQualifiedJavaType("com.inttra.common.EException"));
		cls.addImportedType(new FullyQualifiedJavaType("com.inttra.common.annotations.AEnumColumn"));
		cls.addImportedType(new FullyQualifiedJavaType("com.inttra.common.annotations.AEnumTable"));
		cls.addImportedType(new FullyQualifiedJavaType("com.inttra.shared.data.CBaseEnum"));

		cls.setVisibility(JavaVisibility.PUBLIC);
		cls.setSuperClass("CBaseEnum");

		Field proteField = new Field();
		proteField.setName("prototype");
		proteField.setType(new FullyQualifiedJavaType(className + "Prototype"));
		proteField.setStatic(true);
		proteField.setVisibility(JavaVisibility.PROTECTED);
		proteField.setInitializationString("new " + className + "Prototype()");
		cls.addField(proteField);

		Method constructMethod = new Method();
		constructMethod.setConstructor(true);
		constructMethod.setVisibility(JavaVisibility.PRIVATE);
		constructMethod.setName(className);
		constructMethod.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(),
				"pk"));
		constructMethod.addBodyLine("super(pk);");
		cls.addMethod(constructMethod);

		InnerClass innerClass = new InnerClass(className + "Prototype");
		innerClass.setStatic(true);
		innerClass.setVisibility(JavaVisibility.PUBLIC);
		innerClass.setSuperClass("Prototype<" + className + ">");

		Method innerConstructMethod = new Method();
		innerConstructMethod.setConstructor(true);
		innerConstructMethod.setVisibility(JavaVisibility.PUBLIC);
		innerConstructMethod.setName(className + "Prototype");
		innerConstructMethod.addBodyLine("");
		StringBuffer sb = new StringBuffer(10);
		sb.append("@AEnumTable(");
		sb.append("table = \"" + introspectedTable.getFullyQualifiedTable().getIntrospectedTableName() + "\", ");
		sb.append("primaryKey = \"" + introspectedTable.getPrimaryKeyColumns().get(0).getActualColumnName() + "\", ");
		sb.append("columns = {");
		for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
			String upperField = Character.toUpperCase(introspectedColumn.getJavaProperty().charAt(0)) + introspectedColumn.getJavaProperty().substring(1);
			sb.append("@AEnumColumn(column = \"" + introspectedColumn.getActualColumnName() + "\", method = \"set" + upperField + "\"), ");
		}
		sb.deleteCharAt(sb.length()-2);
		sb.append("}");
		sb.append(")");
		innerConstructMethod.addAnnotation(sb.toString());
		innerClass.addMethod(innerConstructMethod);

		Method enumClass = new Method();
		enumClass.setVisibility(JavaVisibility.PROTECTED);
		enumClass.setName("getEnumClass");
		enumClass.addAnnotation("@Override");
		enumClass.setReturnType(new FullyQualifiedJavaType("Class<" + className + ">"));
		enumClass.addBodyLine("return " + className + ".class;");
		innerClass.addMethod(enumClass);

		Method enumInstance = new Method();
		enumInstance.setVisibility(JavaVisibility.PROTECTED);
		enumInstance.setName("getEnumInstance");
		enumInstance.addAnnotation("@Override");
		enumInstance.setReturnType(new FullyQualifiedJavaType(className));
		enumInstance.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(),
				"key"));
		enumInstance.addBodyLine("return new " + className + "(key);");
		innerClass.addMethod(enumInstance);

		cls.addInnerClass(innerClass);

		Method resolveCode = new Method();
		resolveCode.setVisibility(JavaVisibility.PUBLIC);
		resolveCode.setStatic(true);
		resolveCode.setName("resolve");
		resolveCode.setReturnType(new FullyQualifiedJavaType(className));
		resolveCode.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance().getPrimitiveTypeWrapper(),
				"code"));
		resolveCode.addBodyLine("return resolve(prototype, " + className + ".class, code);");
		cls.addMethod(resolveCode);

		Method resolveName = new Method();
		resolveName.setVisibility(JavaVisibility.PUBLIC);
		resolveName.setStatic(true);
		resolveName.setName("resolve");
		resolveName.setReturnType(new FullyQualifiedJavaType(className));
		resolveName.addException(new FullyQualifiedJavaType("EException"));
		resolveName.addParameter(new Parameter(FullyQualifiedJavaType.getStringInstance(), "name"));
		resolveName.addBodyLine("return resolve(prototype, " + className + ".class, name);");
		cls.addMethod(resolveName);

		Method valueMethod = new Method();
		valueMethod.setVisibility(JavaVisibility.PUBLIC);
		valueMethod.setStatic(true);
		valueMethod.setName("value");
		valueMethod.setReturnType(new FullyQualifiedJavaType(className + "[]"));
		valueMethod.addException(new FullyQualifiedJavaType("EException"));
		valueMethod.addBodyLine("return values(prototype, " + className + ".class);");
		cls.addMethod(valueMethod);

		compilationUnits.add(cls);

	}

	/**
	 * Add class converter.
	 * 
	 * @param compilationUnits
	 * @param introspectedTable
	 */
	private void generateConverter(List<CompilationUnit> compilationUnits, IntrospectedTable introspectedTable) {
		String className = introspectedTable.getTableConfiguration().getDomainObjectName();
		String targetPackage = context.getJavaModelGeneratorConfiguration().getTargetPackage();
		TopLevelClass cls = new TopLevelClass(targetPackage + "." + className + "Converter");
		
		cls.addImportedType(new FullyQualifiedJavaType("java.lang.reflect.Method"));
		cls.addImportedType(new FullyQualifiedJavaType("com.inttra.common.ERuntime"));
		cls.addImportedType(new FullyQualifiedJavaType("com.inttra.shared.booking.NReferenceType"));
		cls.addImportedType(new FullyQualifiedJavaType("com.inttra.shared.data.staticdata.NAutomatchStatus"));
		cls.addImportedType(new FullyQualifiedJavaType("com.inttra.shared.data.staticdata.NEntityType"));
		
		cls.addAnnotation("import com.inttra.common.persistence.util.CColumnMapper.IValueConverter;");
		cls.setVisibility(JavaVisibility.PUBLIC);
		cls.addSuperInterface(new FullyQualifiedJavaType("IValueConverter"));
		
		Method convertSqlMethod = new Method();
		convertSqlMethod.setVisibility(JavaVisibility.PUBLIC);
		convertSqlMethod.setName("convert");
		convertSqlMethod.setReturnType(new FullyQualifiedJavaType("Object"));
		convertSqlMethod.addParameter(new Parameter(FullyQualifiedJavaType.getObjectInstance(), "value"));
		convertSqlMethod.addParameter(new Parameter(FullyQualifiedJavaType.getIntInstance(), "sqlType"));
		convertSqlMethod.addBodyLine("Object ret = null;");
		convertSqlMethod.addBodyLine("if(value==null)");
		convertSqlMethod.addBodyLine("  ret = null;");
		convertSqlMethod.addBodyLine("if(value instanceof NEntityType){");
		convertSqlMethod.addBodyLine("  ret = ((NEntityType)value).getCode();");
		convertSqlMethod.addBodyLine("} else if(value instanceof NReferenceType){");
		convertSqlMethod.addBodyLine("  ret = ((NReferenceType)value).getCode();");
		convertSqlMethod.addBodyLine("} else if(value instanceof NAutomatchStatus){");
		convertSqlMethod.addBodyLine("  ret = ((NAutomatchStatus)value).getCode();");
		convertSqlMethod.addBodyLine("}");
		convertSqlMethod.addBodyLine("return ret;");
		cls.addMethod(convertSqlMethod);
		
		Method convertObjMethod = new Method();
		convertObjMethod.setVisibility(JavaVisibility.PUBLIC);
		convertObjMethod.setName("convert");
		convertObjMethod.setReturnType(new FullyQualifiedJavaType("Object"));
		convertObjMethod.addParameter(new Parameter(FullyQualifiedJavaType.getObjectInstance(), "value"));
		convertObjMethod.addParameter(new Parameter(new FullyQualifiedJavaType("Class<?>"), "targetType"));
		convertObjMethod.addBodyLine("Object ret = null;");
		convertObjMethod.addBodyLine("if(value==null)");
		convertObjMethod.addBodyLine("  ret = null;");
		convertObjMethod.addBodyLine("if(NEntityType.class.isAssignableFrom(targetType) || NReferenceType.class.isAssignableFrom(targetType) || NAutomatchStatus.class.isAssignableFrom(targetType)){");
		convertObjMethod.addBodyLine("Method m = null;");
		convertObjMethod.addBodyLine("try{");
		convertObjMethod.addBodyLine("m = targetType.getMethod(\"resolve\", Integer.class);");
		convertObjMethod.addBodyLine("}catch(Exception e){");
		convertObjMethod.addBodyLine("throw new ERuntime(\"Failed getting resolve method: \" + e.getMessage(), e);");
		convertObjMethod.addBodyLine("}");
		convertObjMethod.addBodyLine("if(m != null){");
		convertObjMethod.addBodyLine("try{");
		convertObjMethod.addBodyLine("ret = m.invoke(null, value);");
		convertObjMethod.addBodyLine("}catch(Throwable t){");
		convertObjMethod.addBodyLine("throw new ERuntime(\"Failed to get value from target object: \" + t.getMessage(), t);");
		convertObjMethod.addBodyLine("}");
		convertObjMethod.addBodyLine("}");
		convertObjMethod.addBodyLine("}");
		convertObjMethod.addBodyLine("return ret;");
		cls.addMethod(convertObjMethod);
		
		compilationUnits.add(cls);
	}

	/**
	 * Add read only interface.
	 * 
	 * @param compilationUnits
	 */
	private void generateReadOnlyInterface(List<CompilationUnit> compilationUnits, IntrospectedTable introspectedTable) {
		String upperName = introspectedTable.getTableConfiguration().getDomainObjectName().substring(1);
		Interface face = new Interface(context.getJavaModelGeneratorConfiguration().getTargetPackage() + ".IR"
				+ upperName);
		face.addImportedType(new FullyQualifiedJavaType("com.inttra.common.util.CDate"));
		face.addImportedType(new FullyQualifiedJavaType("java.math.BigDecimal"));

		face.setVisibility(JavaVisibility.PUBLIC);

		for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
			Method method = new Method();
			String field = introspectedColumn.getJavaProperty();
			String upperField = Character.toUpperCase(field.charAt(0)) + field.substring(1);

			method.setName("get" + upperField);
			method.setVisibility(JavaVisibility.PUBLIC);
			method.setReturnType(new FullyQualifiedJavaType(introspectedColumn.getFullyQualifiedJavaType()
					.getShortName()));

			face.addMethod(method);
		}

		compilationUnits.add(face);
	}

	/**
	 * Add read write interface.
	 * 
	 * @param compilationUnits
	 * @param introspectedTable
	 */
	private void generateReadWriteInterface(List<CompilationUnit> compilationUnits, IntrospectedTable introspectedTable) {
		String upperName = introspectedTable.getTableConfiguration().getDomainObjectName().substring(1);
		Interface face = new Interface(context.getJavaModelGeneratorConfiguration().getTargetPackage() + ".IRW"
				+ upperName);
		face.addImportedType(new FullyQualifiedJavaType("com.inttra.common.util.CDate"));
		face.addImportedType(new FullyQualifiedJavaType("java.math.BigDecimal"));

		face.setVisibility(JavaVisibility.PUBLIC);
		face.addSuperInterface(new FullyQualifiedJavaType(context.getJavaModelGeneratorConfiguration()
				.getTargetPackage() + ".IR" + upperName));

		for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
			Method method = new Method();
			String field = introspectedColumn.getJavaProperty();
			String upperField = Character.toUpperCase(field.charAt(0)) + field.substring(1);

			method.setName("set" + upperField);
			method.setVisibility(JavaVisibility.PUBLIC);
			method.addParameter(new Parameter(new FullyQualifiedJavaType(introspectedColumn.getFullyQualifiedJavaType()
					.getShortName()), field));

			face.addMethod(method);
		}

		compilationUnits.add(face);
	}

	/**
	 * Convert SQL data type of table.
	 */
	@Override
	public void initialized(IntrospectedTable introspectedTable) {

		// check weather a class is enum
		String className = introspectedTable.getTableConfiguration().getDomainObjectName();
		if (className.startsWith("N")) {
			setEnum(true);
		}

		// convert primary key type "BigDecimal" to "Integer"
		for (IntrospectedColumn introspectedColumn : introspectedTable.getPrimaryKeyColumns()) {
			if ("BigDecimal".equals(introspectedColumn.getFullyQualifiedJavaType().getShortName())) {
				introspectedColumn.setFullyQualifiedJavaType(new FullyQualifiedJavaType("Integer"));
			}
		}

		// convert type "Date" to "CDate"
		for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
			if ("Date".equals(introspectedColumn.getFullyQualifiedJavaType().getShortName())) {
				introspectedColumn.setFullyQualifiedJavaType(new FullyQualifiedJavaType("CDate"));
			}
		}
	}

	@Override
	public Properties getProperties() {
		// TODO Auto-generated method stub
		return super.getProperties();
	}

	public boolean isEnum() {
		return isEnum;
	}

	public void setEnum(boolean isEnum) {
		this.isEnum = isEnum;
	}
}
